#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>

#define N 128
#define DEBUG(fmt,...) printf("file:[%s],func:[%s],line:[%d]"fmt,__FILE__,__func__,__LINE__,##__VA_ARGS__)

#define ERROR(msg) do{\
                        printf("file:[%s],func:[%s],line:[%d]",__FILE__,__func__,__LINE__);\
                        perror(msg);\
                        exit(-1);\
                        }while(0);

int main(int argc,const char* argv[])
{

    if(argc != 3){
        ERROR("argc is invalid,argc must be 3!");
    }

    int sockfd=-1;
    int acceptfd=-1;
    struct sockaddr_in serveraddr,clientaddr;
    socklen_t len=sizeof(serveraddr);

    memset(&serveraddr,0,sizeof(serveraddr));
    memset(&clientaddr,0,sizeof(clientaddr));

    sockfd=socket(AF_INET,SOCK_STREAM,0);
    if(sockfd==-1){
        ERROR("socket is failed!");
    }

    serveraddr.sin_family=AF_INET;
    serveraddr.sin_addr.s_addr=inet_addr(argv[1]);
    serveraddr.sin_port=htons(atoi(argv[2]));

    if(bind(sockfd,(struct sockaddr*)&serveraddr,len)==-1){
        ERROR("bind is failed!");
    }

    if(listen(sockfd,5)==-1){
        ERROR("listen is failed!");
    }

    fd_set readfds,tmpfds;
    FD_ZERO(&readfds);
    FD_ZERO(&tmpfds);

    ssize_t recvbytes;
    char buf[N]={0};
    int maxfd=sockfd;
    FD_SET(sockfd,&tmpfds);
    while(1){
        readfds=tmpfds;
        if(select(maxfd+1,&readfds,NULL,NULL,NULL)==-1){
            ERROR("select is failed!");
        }
        for(int i=0;i<=maxfd;i++){
            if(FD_ISSET(i,&readfds)){
                if(i==sockfd){
                    if((acceptfd=accept(sockfd,(struct sockaddr*)&clientaddr,&len))==-1){
                        ERROR("accept is failed!");
                    }
                    printf("Client:[%s,%d]Linked\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
                    FD_SET(acceptfd,&tmpfds);
                    maxfd=maxfd>acceptfd?maxfd:acceptfd;
                }else{
                    memset(buf,0,sizeof(buf));
                    if((recvbytes=recv(i,buf,sizeof(buf),0))==-1){
                        ERROR("recv is failed!");
                    }else if(recvbytes==0||strcmp(buf,"**quit**")==0){
                        printf("Client:[%s,%d]Exit\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
                        FD_CLR(i,&tmpfds);
                        close(i);
                        continue;
                    }
                    printf("buf=%s\n",buf);
                    strcat(buf,"^_^");
                    if(send(i,buf,sizeof(buf),0)==-1){
                        ERROR("send is failed");
                    }
                }
            }
        }
    }
    return 0;
}